#include "Llamadas.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <time.h>

#define SHM_PERMISOS 0666
#define SHM_KEY_CACHE 107
#define SHM_KEY_STRUCT 108

BufferCache * cache; //ambas son para el sistema (mem compartida)
StructFile * structFile;

TDFU tdfu; //para este proceso

int idcache, idstruct; //identificadores de mem compartida
int semCache, semStruct; //semaforos

//para ver mem compartida: ipcs. para borrar mem: ipcrm -m id_mem. para borrar semaforo: ipcrm -s id_sem

//funcion de interceptacion de la senal SIGINT (Ctrl + C)
void my_sigint(int n, siginfo_t *info, void *p) { 
   printf("\nDemonio pid = %d libera la memoria compartida y muere. ¡Adios!\n", getpid());

   //libera semaforos
   semFree(semCache); 
   semFree(semStruct);

   //BufferCache
   if (shmdt(cache) < 0) { //desasignar mem
      fprintf(stderr, "cache shmdt failed: %s\n", strerror(errno));
      exit(1);
   }
   
   if (shmctl(idcache, IPC_RMID, NULL) < 0) { //liberacion mem
      fprintf(stderr, "cache shmctl failed: %s\n", strerror(errno));
      exit(1);
   }

   //Struct File
   if (shmdt(structFile) < 0) { //desasignar mem
      fprintf(stderr, "struct file shmdt failed: %s\n", strerror(errno));
      exit(1);
   }
   
   if (shmctl(idstruct, IPC_RMID, NULL) < 0) { //liberacion mem
      fprintf(stderr, "struct file shmctl failed: %s\n", strerror(errno));
      exit(1);
   } 

   exit(0);
}


void captura_sigint() { //intercepta la senal SIGINT
   struct sigaction act;
   act.sa_flags = SA_SIGINFO; //tres argumentos -> configurar sa_sigaction
   act.sa_sigaction = my_sigint; //(void *)

   if (sigaction(SIGINT, &act, (struct sigaction *) NULL)) { //intercepta señal, arg3: null: accion anterior no se guarda
      printf("Sigaction dio error = %d", errno);
      exit(0);
   }
}


int main() {
   captura_sigint();

   semCache = semInit(SEM_ID_CACHE, VERDE); //semaforo de buffer cache (mem compartida)
   semStruct = semInit(SEM_ID_STRUCT, VERDE); //semaforo de struct file (mem compartida)

   //BufferCache
   idcache = shmget(SHM_KEY_CACHE, sizeof(BufferCache), IPC_CREAT | SHM_PERMISOS); //crea memoria compartida
   if (idcache < 0) {
      fprintf(stderr, "cache shmget failed: %s\n", strerror (errno));
      exit(1);
   }
  
   cache = (BufferCache *) shmat(idcache, (char *) 0, 0); //dato apunta a memoria
   if (cache < (BufferCache *) 0) {
      fprintf (stderr, "cache shmat failed: %s\n", strerror(errno));
      exit(1);
   }  
   

   //Struct File
   idstruct = shmget(SHM_KEY_STRUCT, sizeof(StructFile), IPC_CREAT | SHM_PERMISOS); //crea memoria compartida
   if (idstruct < 0) {
      fprintf(stderr, "struct file shmget failed: %s\n", strerror (errno));
      exit(1);
   }
  
   structFile = (StructFile *) shmat(idstruct, (char *) 0, 0); //dato apunta a memoria
   if (structFile < (StructFile *) 0) {
      fprintf (stderr, "struct file shmat failed: %s\n", strerror(errno));
      exit(1);
   }

   //*********************************************************************************
   captura_usr1_usr2(); //captura senales SIGUSR1 Y SIGUSR2

   //inicializacion de las estructuras
   bc_init();
   struct_init();
   //tdfu_init(); //no hace falta para el demonio


   //prueba
   /*cache->freeStart = 3;
   bc_insertarFreeEnd();
   printf("freeEnd = %d \n", cache->freeEnd);
   printf("freeEnd = %d \n", cache->freeEnd);
   structFile->tam = 7;
   tdfu.tam = 8;*/

   char a = 'a'; //bucle, espera a pulsar 0 para liberar buffer cache y terminar
   while (1) {
      if (a == '1')
         bc_print(); //muestra buffer cache
      else if (a == '2')
         struct_print(); //muestra la struct File
      else if ((a == '0') || (a == 'q'))
         break;

      //a = 'a';
      printf("\nDemonio de BufferCache");
      printf("\n- 1: Mostrar la bufferCache.");
      printf("\n- 2: Mostrar la structFile.");
      printf("\n- 0, q, Ctrl + C: Salir.\n: ");
      a = getchar();
      //prueba: printf("tdfu.tam = %d\n", tdfu.tam);
   }
   
   //******************************** Liberacion de memoria compartida *********************************

   if (kill(getpid(), SIGINT) < 0) //se manda asi mismo la senal: llama a my_sigint()
      perror("error kill en SIGINT: "); 
}

